package cn.net.shuxing.yifu.common.service;


import cn.net.shuxing.yifu.common.bean.*;
import cn.net.shuxing.yifu.common.constant.UserParamConst;
import cn.net.shuxing.yifu.common.constant.UserState;
import cn.net.shuxing.yifu.common.constant.UserType;
import cn.net.shuxing.yifu.common.mapper.UserCapitalMapper;
import cn.net.shuxing.yifu.common.util.CommonExample;
import cn.net.shuxing.yifu.common.util.JedisUtil;
import cn.net.shuxing.yifu.common.util.RedisKeyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class UserCapitalService extends BaseService<UserCapital, UserCapitalMapper> {

    @Autowired
    private DealParamService dealParamService;

    @Autowired
    private CashWalletService cashWalletService;

    @Autowired
    private CoinTypeService coinTypeService;

    @Autowired
    private UserRealInfoService userRealInfoService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private UserCapitalHistoryService userCapitalHistoryService;

    @Autowired
    private UserService userService;

    @Autowired
    private JedisUtil jedisUtil;

    @Autowired
    private OpenPriceHistoryService openPriceHistoryService;

    /**
     * 获取休眠币数量在low到high之间的用户，包括low和high
     *
     * @param low
     * @param high
     * @return
     */
    public List<UserCapital> searchBySleepCoin(Integer coinTypeId, BigDecimal low, BigDecimal high) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.between("sleepCoinCount", low, high)
                .equals("coinTypeId", coinTypeId);
        return mapper.selectByExample(example);
    }

    /**
     * 获取活币数量在low到high之间的用户，包括low和high
     *
     * @param low
     * @param high
     * @return
     */
    public List<UserCapital> searchByAliveCoin(Integer coinTypeId, BigDecimal low, BigDecimal high) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.between("aliveCoinCount", low, high)
                .equals("coinTypeId", coinTypeId);
        return mapper.selectByExample(example);
    }

    public List<UserCapital> getsByUserId(Integer userId) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId);
        return mapper.selectByExample(example);
    }

    public List<UserCapital> getsByUserIdAndType(Integer userId, Integer type) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId);
        example.equals("type", type);
        return mapper.selectByExample(example);
    }

    public List<UserCapital> getsByUserIdAndUserTypeCompleted(Integer userId, Integer userType) {

        if (!userService.checkUser(userId)) {
            return null;
        }
        User user = userService.getByPrimaryKey(userId);
        UserCapital userCapital = new UserCapital();
        userCapital.clearCreateTimeAndUpdateTime();
        userCapital.setUserId(userId);
        userCapital.setType(userType);
        List<UserCapital> userCapitalList = gets(userCapital);
        UserRealInfo userRealInfo = userRealInfoService.getByPrimaryKey(userId);
        if (userRealInfo == null) {
            userCapital.setUserRealName("");
        } else {
            for (UserCapital capital : userCapitalList) {
                capital.setUserRealName(userRealInfo.getRealName());
                capital.setCoinTypeName(coinTypeService.getByPrimaryKey(capital.getCoinTypeId()).getName());
            }
        }
        return userCapitalList;
    }

    public UserCapital getByUserIdAndUserTypeAndCoinTypeId(Integer userId, Integer userType, Integer coinTypeId) {

        if (!userService.checkUser(userId)) {
            return null;
        }
        User user = userService.getByPrimaryKey(userId);
        UserCapital userCapital = new UserCapital();
        userCapital.clearCreateTimeAndUpdateTime();
        userCapital.setUserId(userId);
        userCapital.setType(userType);
        userCapital.setCoinTypeId(coinTypeId);
        UserCapital userCapitalN = get(userCapital);
        UserRealInfo userRealInfo = userRealInfoService.getByPrimaryKey(userId);
        if (userRealInfo == null) {
            userCapital.setUserRealName("");
        } else {
            userCapitalN.setUserRealName(userRealInfo.getRealName());
        }
        userCapitalN.setCoinTypeName(coinTypeService.getByPrimaryKey(userCapitalN.getCoinTypeId()).getName());
        return userCapitalN;
    }

    public UserCapital getsCapitalByUserIdAndUserRole(Integer userId, Integer userRole, Integer coinTypeId) {
        boolean b = userRoleService.hasRole(userId, userRole);
        if (b) {
            return getByUserIdAndUserTypeAndCoinTypeId(userId, userRole, coinTypeId);
        } else {
            return null;
        }
    }

    public List<UserCapital> getsByUserIdAndUserType(Integer userId, Integer type) {
        if (!userService.checkUser(userId)) {
            return null;
        }
        User user = userService.getByPrimaryKey(userId);
        UserCapital userCapital = new UserCapital();
        userCapital.clearCreateTimeAndUpdateTime();
        userCapital.setUserId(userId);
        userCapital.setType(type);
        return gets(userCapital);
    }

    public UserCapital insert(Integer userId, Integer coinTypeId, LocalDateTime invalidTime, BigDecimal aliveCoinCount, BigDecimal sleepCoinCount, int type) {
        UserCapital userCapital = new UserCapital();
        userCapital.setUserId(userId);
        userCapital.setCoinTypeId(coinTypeId);
        userCapital.setInvalidTime(invalidTime);
        userCapital.setAliveCoinCount(aliveCoinCount);
        userCapital.setSleepCoinCount(sleepCoinCount);
        userCapital.setType(type);
        insert(userCapital);

        UserCapitalHistory userCapitalHistory = new UserCapitalHistory();
        userCapitalHistory.setUserId(userCapital.getUserId());
        userCapitalHistory.setAliveCoinCount(userCapital.getAliveCoinCount());
        userCapitalHistory.setSleepCoinCount(userCapital.getSleepCoinCount());
        userCapitalHistory.setCoinTypeId(userCapital.getCoinTypeId());
        userCapitalHistory.setType(type);
        userCapitalHistoryService.insert(userCapitalHistory);

        return getByPrimaryKey(userCapital.getId());
    }

    public void addAliveCoin(Integer userId, Integer coinTypeId, BigDecimal aliveCoinCount, int type) {
        if (!userService.checkUser(userId))
            return;
        UserCapital userCapital = getByUserIdAndCoinTypeIdAndUserTypeIfNo(userId, coinTypeId, type);
        BigDecimal aliveCoinCount1 = userCapital.getAliveCoinCount();
        aliveCoinCount = aliveCoinCount.add(aliveCoinCount1);
        userCapital.setAliveCoinCount(aliveCoinCount);
        update(userCapital);

    }

    public UserCapital getByUserIdAndCoinTypeId(Integer userId, Integer coinTypeId) {
        User user = userService.getByPrimaryKey(userId);
        if (user == null)
            return null;
        Integer type = user.getType();
        return getByUserIdAndCoinTypeIdAndUserType(userId, coinTypeId, type);
    }

    public void reduceAliveCoin(Integer userId, Integer coinTypeId, BigDecimal aliveCoinCount, int type) {
        aliveCoinCount = new BigDecimal(0).subtract(aliveCoinCount);
        addAliveCoin(userId, coinTypeId, aliveCoinCount, type);
    }

    public void addSleepCoin(Integer userId, Integer coinTypeId, BigDecimal sleepCoinCount) {
        if (!userService.checkUser(userId))
            return;
        UserCapital userCapital = getByUserIdAndCoinTypeIdAndUserType(userId, coinTypeId, UserType.SHAREHOLDER);
        if (userCapital == null) {
            User user = userService.getByPrimaryKey(userId);
            insert(userId, coinTypeId, null, new BigDecimal(0), new BigDecimal(0), UserType.SHAREHOLDER);
        }
        BigDecimal sleepCoinCount1 = userCapital.getSleepCoinCount();
        sleepCoinCount = sleepCoinCount.add(sleepCoinCount1);
        userCapital.setSleepCoinCount(sleepCoinCount);
        update(userCapital);
    }

    public void reduceSleepCoin(Integer userId, Integer coinTypeId, BigDecimal sleepCoinCount) {
        sleepCoinCount = new BigDecimal(0).subtract(sleepCoinCount);
        addSleepCoin(userId, coinTypeId, sleepCoinCount);
    }

    @Override
    public int update(UserCapital bean) {
        if (super.update(bean) < 1) {
            return -1;
        } else {
            UserCapitalHistory userCapitalHistory = new UserCapitalHistory();
            userCapitalHistory.setUserId(bean.getUserId());
            userCapitalHistory.setAliveCoinCount(bean.getAliveCoinCount());
            userCapitalHistory.setSleepCoinCount(bean.getSleepCoinCount());
            userCapitalHistory.setCoinTypeId(bean.getCoinTypeId());
            return userCapitalHistoryService.insert(userCapitalHistory);
        }
    }

    @Override
    protected void complete(UserCapital bean) {
        if (bean == null)
            return;
        Integer coinTypeId = bean.getCoinTypeId();
        BigDecimal openPrice = openPriceHistoryService.getOpenPrice(coinTypeId);
        bean.setOpenPrice(openPrice);
    }

    public UserCapital getByUserIdAndCoinTypeIdAndUserType(Integer userId, Integer coinTypeId, int type) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId)
                .equals("coinTypeId", coinTypeId)
                .equals("type", type);
        UserCapital userCapital = mapper.selectOneByExample(example);
        complete(userCapital);
        return userCapital;
    }

    public UserCapital getByUserIdAndCoinTypeIdAndUserTypeIfNo(Integer userId, Integer coinTypeId, int type) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId)
                .equals("coinTypeId", coinTypeId)
                .equals("type", type);
        UserCapital userCapital = mapper.selectOneByExample(example);
        if (userCapital == null) {
            userCapital = insert(userId, coinTypeId, null, new BigDecimal(0), new BigDecimal(0), type);
        }
        return userCapital;
    }

    public UserCapital getByUserIdAndCoinTypeIdAndUserTypeWithoutComplete(Integer userId, Integer coinTypeId, int type) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId)
                .equals("coinTypeId", coinTypeId)
                .equals("type", type);
        UserCapital userCapital = mapper.selectOneByExample(example);
        return userCapital;
    }

    public List<UserCapital> getByUserIdAndUserTypeWithoutComplete(Integer userId, int type) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("userId", userId)
                .equals("type", type);
        List<UserCapital> userCapitals = mapper.selectByExample(example);
        return userCapitals;
    }

    public boolean addDealCount(int userId, int coinTypeId, BigDecimal count) {
        UserCapital userCapital = getByUserIdAndCoinTypeIdAndUserType(userId, coinTypeId, UserType.MEMBER);
        if (userCapital == null)
            return false;
        userCapital.setTotalDealCount(userCapital.getTotalDealCount().add(count));
        update(userCapital);
        return true;
    }

    public boolean addDealCount(int userId, int coinTypeId, BigDecimal count, int userType) {
        UserCapital userCapital = getByUserIdAndCoinTypeIdAndUserType(userId, coinTypeId, userType);
        if (userCapital == null)
            return false;
        userCapital.setTotalDealCount(userCapital.getTotalDealCount().add(count));
        update(userCapital);
        return true;
    }

    public List<UserCapital> getsByCoinType(Integer coinTypeId) {
        CommonExample example = new CommonExample(UserCapital.class);
        example.equals("coinTypeId", coinTypeId);
        return getsByExampleWithoutComplete(example);
    }

    //会员总资产折算=活币总价值+现金钱包余额
    public BigDecimal getMemberTotalCapitalConvert(Integer userId) {
        List<UserCapital> userCapitals = getsByUserId(userId);
        BigDecimal totalCapitalConvert = cashWalletService.getByUserId(userId).getCashCount();
        if (userCapitals != null && !userCapitals.isEmpty()) {
            for (UserCapital userCapital : userCapitals) {
                BigDecimal capitalConvert = new BigDecimal(0);
                BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(userCapital.getCoinTypeId())));
                BigDecimal aliveCoinCount = userCapital.getAliveCoinCount();
                capitalConvert = openPrice.multiply(aliveCoinCount);
                totalCapitalConvert = totalCapitalConvert.add(capitalConvert);
            }
        }
        return totalCapitalConvert;
    }

    //会员可用折合:判断用户状态 1.正常  总资产-钱包最小持有量*单价   2.冻结/封号 只显示现金钱包余额
    public BigDecimal getMemberUsAbleTotalCount(Integer userId) {
        BigDecimal memberUsAbleTotalCount = cashWalletService.getByUserId(userId).getCashCount();
        Integer state = userService.getByPrimaryKey(userId).getState();
        if (state == UserState.OK) {
            List<UserCapital> userCapitals = getsByUserIdAndUserType(userId, UserType.MEMBER);
            if (userCapitals != null && !userCapitals.isEmpty()) {
                for (UserCapital userCapital : userCapitals) {
                    //单价
                    BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(userCapital.getCoinTypeId())));
                    //最小持有量
                    BigDecimal minCount = new BigDecimal(dealParamService.getValue(userId, userCapital.getCoinTypeId(), UserParamConst.ACTIVATE_WALLET_NEED_MIN_COUNT));
                    //单币种持有量
                    BigDecimal aliveCount = userCapital.getAliveCoinCount();
                    //单币种可用价值
                    BigDecimal oneCoinUsAbleCount = (aliveCount.subtract(minCount)).multiply(openPrice);
                    memberUsAbleTotalCount = memberUsAbleTotalCount.add(oneCoinUsAbleCount);
                }
            }
        }
        return memberUsAbleTotalCount;
    }

    //会员冻结折合:  判断用户状态 1.正常 冻结折合=各币种最低持有量*单价  2.非正常 冻结折合=活币总价值
    public BigDecimal getMemberFrozenTotalCount(Integer userId) {
        BigDecimal memberFrozenTotalCount = new BigDecimal(0);
        List<UserCapital> userCapitals = getsByUserId(userId);
        Integer state = userService.getByPrimaryKey(userId).getState();
        if (userCapitals != null && userCapitals.isEmpty()) {
            for (UserCapital userCapital : userCapitals) {
                //单价
                BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(userCapital.getCoinTypeId())));
                //最低持有量
                BigDecimal minCount = new BigDecimal(dealParamService.getValue(userId, userCapital.getCoinTypeId(), UserParamConst.MEMBER_KEEP_ALIVE_COIN_MIN_COUNT));
                if (state == UserState.OK) {
                    memberFrozenTotalCount = memberFrozenTotalCount.add((openPrice.multiply(minCount)));
                } else {
                    BigDecimal aliveCoinCount = userCapital.getAliveCoinCount();
                    memberFrozenTotalCount = memberFrozenTotalCount.add((aliveCoinCount.multiply(minCount)));
                }
            }
        }
        return memberFrozenTotalCount;
    }

    //股东总资产折算=活币+休眠币+现金钱包
    public BigDecimal getShareholderTotalCapitalConvert(Integer userId) {
        BigDecimal shareholderTotalCapitalConvert = cashWalletService.getByUserId(userId).getCashCount();
        List<UserCapital> userCapitals = getsByUserId(userId);
        if (userCapitals != null && !userCapitals.isEmpty()) {
            for (UserCapital userCapital : userCapitals) {
                BigDecimal aliveCoinCount = userCapital.getAliveCoinCount();
                BigDecimal sleepCoinCount = userCapital.getSleepCoinCount();
                BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(userCapital.getCoinTypeId())));
                BigDecimal totalCount = aliveCoinCount.add(sleepCoinCount);
                shareholderTotalCapitalConvert = shareholderTotalCapitalConvert.add(openPrice.multiply(totalCount));
            }
        }
        return shareholderTotalCapitalConvert;
    }

    //股东可用折合  判断用户状态 1.正常=股东总资产折合 2.非正常=现金钱包
    public BigDecimal getShareholderUsAbleTotalCount(Integer userId) {
        BigDecimal shareholderUsAbleTotalCount = cashWalletService.getByUserId(userId).getCashCount();
        Integer state = userService.getByPrimaryKey(userId).getState();
        if (state == UserState.OK) {
            shareholderUsAbleTotalCount = getShareholderTotalCapitalConvert(userId);
        }
        return shareholderUsAbleTotalCount;
    }

    //股东冻结折合 判断用户状态 1.正常=休眠币*单价 .2非正常=活币+休眠币 *单价
    public BigDecimal getShareholderFrozenTotalCount(Integer userId) {
        BigDecimal shareholderFrozenTotalCount = new BigDecimal(0);
        Integer state = userService.getByPrimaryKey(userId).getState();
        List<UserCapital> userCapitals = getsByUserId(userId);
        if (userCapitals != null && !userCapitals.isEmpty()) {
            for (UserCapital userCapital : userCapitals) {
                BigDecimal frozenCount = new BigDecimal(0);
                BigDecimal openPrice = new BigDecimal(jedisUtil.get(RedisKeyCreator.openPrice(userCapital.getCoinTypeId())));
                if (state != UserState.OK) {
                    frozenCount = userCapital.getSleepCoinCount();
                } else {
                    frozenCount = frozenCount.add(userCapital.getAliveCoinCount()).add(userCapital.getSleepCoinCount());
                }
                shareholderFrozenTotalCount = shareholderFrozenTotalCount.add((frozenCount.multiply(openPrice)));
            }
        }
        return shareholderFrozenTotalCount;
    }

    //将一个会员的资产转移到另外另外一个股东下
    public boolean capitalTransfer(Integer newMan, Integer oldMan) {
        boolean flag = false;
        List<UserCapital> newManCapital = getsByUserId(newMan);
        List<UserCapital> oldManCapital = getsByUserId(oldMan);
        // TODO: 2019-05-27 需要增加用户多币种情况下 用户币种多余老用户的操作
        if (newManCapital != null && !newManCapital.isEmpty()) {
            for (UserCapital userCapital : newManCapital) {
                BigDecimal newManAliveCoinCount = userCapital.getAliveCoinCount();
                Integer newManCoinTypeId = userCapital.getCoinTypeId();
                BigDecimal newManTotalDealCount = userCapital.getTotalDealCount();
                if (oldManCapital != null && !oldManCapital.isEmpty()) {
                    for (UserCapital capital : oldManCapital) {
                        BigDecimal oldManAliveCoinCount = capital.getAliveCoinCount();
                        Integer oldManCoinTypeId = capital.getCoinTypeId();
                        BigDecimal oldManTotalDealCount = capital.getTotalDealCount();
                        if (newManCoinTypeId == oldManCoinTypeId) {
                            oldManAliveCoinCount = oldManAliveCoinCount.add(newManAliveCoinCount);
                            oldManTotalDealCount = oldManTotalDealCount.add(newManTotalDealCount);
                            capital.setAliveCoinCount(oldManAliveCoinCount);
                            capital.setTotalDealPrice(oldManTotalDealCount);
                            update(capital);
                        }
                    }
                }
                userCapital.setDeleted(1);
                update(userCapital);
                flag = true;
            }
        } else {
            flag = true;
        }
        return flag;
    }

    public boolean cashTransfer(Integer newMan, Integer oldMan) {
        CashWallet newManCashWallet = cashWalletService.getByUserId(newMan);
        CashWallet oldManCashWallet = cashWalletService.getByUserId(oldMan);
        BigDecimal newCashCount = newManCashWallet.getCashCount();
        BigDecimal oldCashCount = oldManCashWallet.getCashCount();
        oldCashCount = oldCashCount.add(newCashCount);
        oldManCashWallet.setCashCount(oldCashCount);
        newManCashWallet.setDeleted(1);
        cashWalletService.update(newManCashWallet);
        cashWalletService.update(oldManCashWallet);
        return true;
    }
}
